package com.yiyuan.app.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.guaike.core.entity.result.Result;
import com.guaike.core.redis.context.ApiContext;
import com.yiyuan.app.dao.*;
import com.yiyuan.app.entity.enums.*;
import com.yiyuan.app.entity.param.BaseIdDTO;
import com.yiyuan.app.entity.param.BattleDTO;
import com.yiyuan.app.entity.po.*;
import com.yiyuan.app.entity.result.*;
import com.yiyuan.app.service.BaseUtilService;
import com.yiyuan.app.service.TaskService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
@AllArgsConstructor
public class TaskServiceImpl implements TaskService {

    private final MRecordTaskDailyDAO mRecordTaskDailyDAO;
    private final MRecordTaskDAO mRecordTaskDAO;
    private final UAppUserEquityDAO uAppUserEquityDAO;
    private final MConfVipDAO mConfVipDAO;
    private final MRankBattleRecreationDAO mRankBattleRecreationDAO;
    private final MRankBattleArcadeMachineDAO mRankBattleArcadeMachineDAO;
    private final MRankBattlePushCoinsDAO mRankBattlePushCoinsDAO;
    private final MRecordBattleArcadeMachineDAO mRecordBattleArcadeMachineDAO;
    private final MRecordBattlePushCoinsDAO mRecordBattlePushCoinsDAO;
    private final MRecordBattleRecreationDAO mRecordBattleRecreationDAO;
    private final DDetailsPineconeDAO dDetailsPineconeDAO;
    private final BaseUtilService baseUtilService;

    @Override
    public Result<List<TaskDailyVO>> dailyList() {
        AppUser currentUser = ApiContext.getCurrentUser();
        List<MRecordTaskDailyPO> pos = mRecordTaskDailyDAO.findUserTodayList(currentUser.getUserId(), LocalDate.now());
        List<TaskDailyVO> list = new ArrayList<>();
        pos.forEach(po -> {
            TaskDailyVO vo = new TaskDailyVO();
            BeanUtils.copyProperties(po, vo);
            vo.setCondition(po.getThreshold());
            if (DailyTaskActionEnum.total_recharge.getCode().equals(po.getAction())) {
                vo.setCurrentProgress(po.getCurrentProgress() / 100);
            }
            list.add(vo);
        });
        List<TaskDailyVO> unclainmedList = list.stream().filter(vo -> vo.getStatus().equals(TaskStatusEnum.unclaimed.getCode())).collect(Collectors.toList());
        List<TaskDailyVO> statusList = list.stream().filter(vo -> !vo.getStatus().equals(TaskStatusEnum.unclaimed.getCode())).collect(Collectors.toList());
        statusList = statusList.stream().sorted(Comparator.comparing(TaskDailyVO::getStatus)).collect(Collectors.toList());
        list.clear();
        list.addAll(unclainmedList);
        list.addAll(statusList);
        return Result.success().data(list).build();
    }

    @Override
    public Result<List<TaskActionVO>> taskActionList() {
        List<TaskActionVO> list = new ArrayList<>();
        for (TaskActionEnum actionEnum : TaskActionEnum.values()) {
            TaskActionVO vo = new TaskActionVO();
            vo.setAction(actionEnum.getCode());
            vo.setActionDesc(actionEnum.getDesc());
            list.add(vo);
        }
        return Result.success().data(list).build();
    }

    @Override
    public Result<List<TaskVO>> taskList(Integer action) {
        AppUser currentUser = ApiContext.getCurrentUser();
        List<MRecordTaskPO> pos = mRecordTaskDAO.findList(currentUser.getUserId(), action, Collections.singletonList(TaskStatusEnum.unclaimed.getCode()));
        List<MRecordTaskPO> pos1 = mRecordTaskDAO.findList(currentUser.getUserId(), action, Arrays.asList(TaskStatusEnum.go_complete.getCode(), TaskStatusEnum.received_already.getCode()));
        pos.addAll(pos1);
        UAppUserEquityPO equityPO = uAppUserEquityDAO.findOne(UAppUserEquityPO::getUserId, currentUser.getUserId());
        List<TaskVO> list = new ArrayList<>();
        pos.forEach(po -> {
            TaskVO vo = new TaskVO();
            BeanUtils.copyProperties(po, vo);
            vo.setUnlock(equityPO.getVipGrade() >= po.getVipLevel());
            vo.setCondition(po.getThreshold());
            if (action.equals(TaskActionEnum.total_recharge.getCode())) {
                vo.setCurrentProgress(po.getCurrentProgress() / 100);
            }
            list.add(vo);
        });
        return Result.success().data(list).build();
    }

    @Override
    public Result<VipLevelVO> vipProgress() {
        VipLevelVO vo = new VipLevelVO();
        AppUser currentUser = ApiContext.getCurrentUser();
        UAppUserEquityPO equityPO = uAppUserEquityDAO.findOne(UAppUserEquityPO::getUserId, currentUser.getUserId());
        vo.setMyVipLevel(equityPO.getVipGrade());
        vo.setMyRechargeMoney(equityPO.getRechargeMoney());
        MConfVipPO vipPO = mConfVipDAO.findOne(MConfVipPO::getVipLevel, vo.getMyVipLevel() + 1);
        if (Objects.nonNull(vipPO)) {
            vo.setNextVipLevel(vipPO.getVipLevel());
            vo.setNextThreshold(vipPO.getThreshold());
            vo.setGiveRate(vipPO.getGiveRate());
        }
        MConfVipPO myVipPO = mConfVipDAO.findOne(MConfVipPO::getVipLevel, equityPO.getVipGrade());
        if (Objects.nonNull(myVipPO)) {
            vo.setCurrentGiveRate(myVipPO.getGiveRate());
        }
        return Result.success().data(vo).build();
    }

    @Override
    public Result<List<ChallengeRankVO>> challengeRankList(Integer roomType) {
        if (Objects.isNull(RoomTypeEnum.getByCode(roomType))) {
            return Result.failure().message("榜单类型不正确").build();
        }
        AppUser currentUser = ApiContext.getCurrentUser();
        List<ChallengeRankVO> vos = new ArrayList<>();
        if (RoomTypeEnum.push_coins.getCode().equals(roomType)) {
            List<MRankBattlePushCoinsPO> rankList = mRankBattlePushCoinsDAO.findBattleRankList();
            rankList.forEach(po -> {
                ChallengeRankVO vo = new ChallengeRankVO();
                BeanUtils.copyProperties(po, vo);
                vo.setNickname(po.getNickname());
                vos.add(vo);
            });
        } else if (RoomTypeEnum.arcade_machine.getCode().equals(roomType)) {
            List<MRankBattleArcadeMachinePO> rankList = mRankBattleArcadeMachineDAO.findBattleRankList();
            rankList.forEach(po -> {
                ChallengeRankVO vo = new ChallengeRankVO();
                BeanUtils.copyProperties(po, vo);
                vo.setNickname(po.getNickname());
                vos.add(vo);
            });
        } else {
            List<MRankBattleRecreationPO> rankList = mRankBattleRecreationDAO.findBattleRankList();
            rankList.forEach(po -> {
                ChallengeRankVO vo = new ChallengeRankVO();
                BeanUtils.copyProperties(po, vo);
                vo.setNickname(po.getNickname());
                vos.add(vo);
            });
        }
        vos.forEach(vo -> {
            if (RoomTypeEnum.push_coins.getCode().equals(roomType)) {
                MRecordBattlePushCoinsPO po = mRecordBattlePushCoinsDAO.findOneByUserId(vo.getId(), currentUser.getUserId());
                if (Objects.isNull(po)) {
                    vo.setStatus(BattleStatusEnum.go_battle.getCode());
                } else {
                    vo.setStatus(po.getStatus());
                }
            } else if (RoomTypeEnum.arcade_machine.getCode().equals(roomType)) {
                MRecordBattleArcadeMachinePO po = mRecordBattleArcadeMachineDAO.findOneByUserId(vo.getId(), currentUser.getUserId());
                if (Objects.isNull(po)) {
                    vo.setStatus(BattleStatusEnum.go_battle.getCode());
                } else {
                    vo.setStatus(po.getStatus());
                }
            } else {
                MRecordBattleRecreationPO po = mRecordBattleRecreationDAO.findOneByUserId(vo.getId(), currentUser.getUserId());
                if (Objects.isNull(po)) {
                    vo.setStatus(BattleStatusEnum.go_battle.getCode());
                } else {
                    vo.setStatus(po.getStatus());
                }
            }
        });
        return Result.success().data(vos).build();
    }

    @Override
    @Transactional
    public Result<Boolean> getDailyTask(BaseIdDTO param) {
        AppUser currentUser = ApiContext.getCurrentUser();
        MRecordTaskDailyPO dailyPO = mRecordTaskDailyDAO.findById(param.getId());
        if (Objects.isNull(dailyPO)) {
            return Result.failure().message("记录不存在").build();
        }
        if (dailyPO.getStatus().equals(TaskStatusEnum.go_complete.getCode())) {
            return Result.failure().message("该任务还未完成，不能领取").build();
        }
        if (dailyPO.getStatus().equals(TaskStatusEnum.received_already.getCode())) {
            return Result.failure().message("该任务已领取，不能重复领取").build();
        }
        DDetailsPineconePO po = new DDetailsPineconePO();
        po.setUserId(currentUser.getUserId());
        po.setLabelType(LabelTypeEnum.daily_task.getCode());
        po.setDetailsType(DetailsTypeEnum.income.getCode());
        po.setPinecone(dailyPO.getPrize());
        dDetailsPineconeDAO.save(po);
        uAppUserEquityDAO.addPinecone(currentUser.getUserId(), dailyPO.getPrize());
        dailyPO.setStatus(TaskStatusEnum.received_already.getCode());
        mRecordTaskDailyDAO.updateById(dailyPO);
        return Result.success().data(Boolean.TRUE).build();
    }

    @Override
    @Transactional
    public Result<Boolean> getTask(BaseIdDTO param) {
        AppUser currentUser = ApiContext.getCurrentUser();
        MRecordTaskPO taskPO = mRecordTaskDAO.findById(param.getId());
        if (Objects.isNull(taskPO)) {
            return Result.failure().message("记录不存在").build();
        }
        if (taskPO.getStatus().equals(TaskStatusEnum.go_complete.getCode())) {
            return Result.failure().message("该任务还未完成，不能领取").build();
        }
        if (taskPO.getStatus().equals(TaskStatusEnum.received_already.getCode())) {
            return Result.failure().message("该任务已领取，不能重复领取").build();
        }
        UAppUserEquityPO equityPO = uAppUserEquityDAO.findOne(UAppUserEquityPO::getUserId, currentUser.getUserId());
        if (equityPO.getVipGrade() < taskPO.getVipLevel()) {
            return Result.failure().message("未达到等级，不能领取").build();
        }
        DDetailsPineconePO po = new DDetailsPineconePO();
        po.setUserId(currentUser.getUserId());
        po.setLabelType(LabelTypeEnum.task.getCode());
        po.setDetailsType(DetailsTypeEnum.income.getCode());
        po.setPinecone(taskPO.getPrize());
        dDetailsPineconeDAO.save(po);
        uAppUserEquityDAO.addPinecone(currentUser.getUserId(), taskPO.getPrize());
        taskPO.setStatus(TaskStatusEnum.received_already.getCode());
        mRecordTaskDAO.updateById(taskPO);
        return Result.success().data(Boolean.TRUE).build();
    }

    @Override
    @Transactional
    public Result<Boolean> initiateBattle(BattleDTO param) {
        AppUser currentUser = ApiContext.getCurrentUser();
        LocalDate now = LocalDate.now();
        if (RoomTypeEnum.push_coins.getCode().equals(param.getBattleType())) {
            MRankBattlePushCoinsPO po = mRankBattlePushCoinsDAO.findById(param.getId());
            if (Objects.isNull(po)) {
                return Result.failure().message("记录不存在").build();
            }
            MRecordBattlePushCoinsPO recordPO = mRecordBattlePushCoinsDAO.findOneByUserId(param.getId(), currentUser.getUserId());
            if (Objects.nonNull(recordPO)) {
                return Result.failure().message("该记录已发起挑战，请勿重复挑战").build();
            }
            long count = mRecordBattlePushCoinsDAO.count(new LambdaQueryWrapper<MRecordBattlePushCoinsPO>().eq(MRecordBattlePushCoinsPO::getUserId, currentUser.getUserId()).eq(MRecordBattlePushCoinsPO::getBattleDate, LocalDate.now()));
            if (count >= 5) {
                return Result.failure().message("今日推推乐挑战次数已用完").build();
            }
            MRecordBattlePushCoinsPO battlePO = mRecordBattlePushCoinsDAO.findLatestBattleByUserId(currentUser.getUserId());
            if (Objects.nonNull(battlePO) && battlePO.getStatus().equals(BattleStatusEnum.battling.getCode())) {
                battlePO.setStatus(BattleStatusEnum.failed.getCode());
                mRecordBattlePushCoinsDAO.updateById(battlePO);
            }
            MRecordBattlePushCoinsPO coinsPO = new MRecordBattlePushCoinsPO();
            coinsPO.setBattleId(param.getId());
            coinsPO.setUserId(currentUser.getUserId());
            coinsPO.setStatus(BattleStatusEnum.battling.getCode());
            coinsPO.setBattleDate(now);
            mRecordBattlePushCoinsDAO.save(coinsPO);
        } else if (RoomTypeEnum.arcade_machine.getCode().equals(param.getBattleType())) {
            MRankBattleArcadeMachinePO po = mRankBattleArcadeMachineDAO.findById(param.getId());
            if (Objects.isNull(po)) {
                return Result.failure().message("记录不存在").build();
            }
            MRecordBattleArcadeMachinePO recordPO = mRecordBattleArcadeMachineDAO.findOneByUserId(param.getId(), currentUser.getUserId());
            if (Objects.nonNull(recordPO)) {
                return Result.failure().message("该记录已发起挑战，请勿重复挑战").build();
            }
            long count = mRecordBattleArcadeMachineDAO.count(new LambdaQueryWrapper<MRecordBattleArcadeMachinePO>().eq(MRecordBattleArcadeMachinePO::getUserId, currentUser.getUserId()).eq(MRecordBattleArcadeMachinePO::getBattleDate, LocalDate.now()));
            if (count >= 5) {
                return Result.failure().message("今日潮玩挑战次数已用完").build();
            }
            MRecordBattleArcadeMachinePO battlePO = mRecordBattleArcadeMachineDAO.findLatestBattleByUserId(currentUser.getUserId());
            if (Objects.nonNull(battlePO) && battlePO.getStatus().equals(BattleStatusEnum.battling.getCode())) {
                battlePO.setStatus(BattleStatusEnum.failed.getCode());
                mRecordBattleArcadeMachineDAO.updateById(battlePO);
            }
            MRecordBattleArcadeMachinePO arcadeMachinePO = new MRecordBattleArcadeMachinePO();
            arcadeMachinePO.setBattleId(param.getId());
            arcadeMachinePO.setUserId(currentUser.getUserId());
            arcadeMachinePO.setStatus(BattleStatusEnum.battling.getCode());
            arcadeMachinePO.setBattleDate(now);
            mRecordBattleArcadeMachineDAO.save(arcadeMachinePO);
        } else {
            MRankBattleRecreationPO po = mRankBattleRecreationDAO.findById(param.getId());
            if (Objects.isNull(po)) {
                return Result.failure().message("记录不存在").build();
            }
            MRecordBattleRecreationPO recordPO = mRecordBattleRecreationDAO.findOneByUserId(param.getId(), currentUser.getUserId());
            if (Objects.nonNull(recordPO)) {
                return Result.failure().message("该记录已发起挑战，请勿重复挑战").build();
            }
            long count = mRecordBattleRecreationDAO.count(new LambdaQueryWrapper<MRecordBattleRecreationPO>().eq(MRecordBattleRecreationPO::getUserId, currentUser.getUserId()).eq(MRecordBattleRecreationPO::getBattleDate, LocalDate.now()));
            if (count >= 5) {
                return Result.failure().message("今日娱乐挑战次数已用完").build();
            }
            MRecordBattleRecreationPO battlePO = mRecordBattleRecreationDAO.findLatestBattleByUserId(currentUser.getUserId());
            if (Objects.nonNull(battlePO) && battlePO.getStatus().equals(BattleStatusEnum.battling.getCode())) {
                battlePO.setStatus(BattleStatusEnum.failed.getCode());
                mRecordBattleRecreationDAO.updateById(battlePO);
            }
            MRecordBattleRecreationPO recreationPO = new MRecordBattleRecreationPO();
            recreationPO.setBattleId(param.getId());
            recreationPO.setUserId(currentUser.getUserId());
            recreationPO.setStatus(BattleStatusEnum.battling.getCode());
            recreationPO.setBattleDate(now);
            mRecordBattleRecreationDAO.save(recreationPO);
        }
        //完成每日任务
        String dailyKey = currentUser.getUserId() + now.toString() + "dailyTask";
        baseUtilService.setDailyTask(dailyKey, currentUser.getUserId(), now);
        mRecordTaskDailyDAO.updateFirstBattle(currentUser.getUserId(), now);
        baseUtilService.dealDailyTaskAllComplete(currentUser.getUserId(), now);
        return Result.success().data(Boolean.TRUE).build();
    }

    @Override
    public Result<Boolean> getBattlePrize(BattleDTO param) {
        AppUser currentUser = ApiContext.getCurrentUser();
        Integer prize;
        if (RoomTypeEnum.push_coins.getCode().equals(param.getBattleType())) {
            MRankBattlePushCoinsPO po = mRankBattlePushCoinsDAO.findById(param.getId());
            if (Objects.isNull(po)) {
                return Result.failure().message("记录不存在").build();
            }
            MRecordBattlePushCoinsPO recordPO = mRecordBattlePushCoinsDAO.findOneByUserId(param.getId(), currentUser.getUserId());
            if (Objects.isNull(recordPO)) {
                return Result.failure().message("你没有对他发起挑战，不能领取奖励").build();
            }
            if (recordPO.getStatus().equals(BattleStatusEnum.battling.getCode())
                    || recordPO.getStatus().equals(BattleStatusEnum.failed.getCode())) {
                return Result.failure().message("本次挑战不能领取奖励").build();
            }
            if (recordPO.getStatus().equals(BattleStatusEnum.received_already.getCode())) {
                return Result.failure().message("本次挑战已领取奖励，不能重复领取").build();
            }
            recordPO.setStatus(BattleStatusEnum.received_already.getCode());
            mRecordBattlePushCoinsDAO.updateById(recordPO);
            prize = po.getPinecone();
        } else if (RoomTypeEnum.arcade_machine.getCode().equals(param.getBattleType())) {
            MRankBattleArcadeMachinePO po = mRankBattleArcadeMachineDAO.findById(param.getId());
            if (Objects.isNull(po)) {
                return Result.failure().message("记录不存在").build();
            }
            MRecordBattleArcadeMachinePO recordPO = mRecordBattleArcadeMachineDAO.findOneByUserId(param.getId(), currentUser.getUserId());
            if (Objects.isNull(recordPO)) {
                return Result.failure().message("你没有对他发起挑战，不能领取奖励").build();
            }
            if (recordPO.getStatus().equals(BattleStatusEnum.battling.getCode())
                    || recordPO.getStatus().equals(BattleStatusEnum.failed.getCode())) {
                return Result.failure().message("本次挑战不能领取奖励").build();
            }
            if (recordPO.getStatus().equals(BattleStatusEnum.received_already.getCode())) {
                return Result.failure().message("本次挑战已领取奖励，不能重复领取").build();
            }
            recordPO.setStatus(BattleStatusEnum.received_already.getCode());
            mRecordBattleArcadeMachineDAO.updateById(recordPO);
            prize = po.getPinecone();
        } else {
            MRankBattleRecreationPO po = mRankBattleRecreationDAO.findById(param.getId());
            if (Objects.isNull(po)) {
                return Result.failure().message("记录不存在").build();
            }
            MRecordBattleRecreationPO recordPO = mRecordBattleRecreationDAO.findOneByUserId(param.getId(), currentUser.getUserId());
            if (Objects.isNull(recordPO)) {
                return Result.failure().message("你没有对他发起挑战，不能领取奖励").build();
            }
            if (recordPO.getStatus().equals(BattleStatusEnum.battling.getCode())
                    || recordPO.getStatus().equals(BattleStatusEnum.failed.getCode())) {
                return Result.failure().message("本次挑战不能领取奖励").build();
            }
            if (recordPO.getStatus().equals(BattleStatusEnum.received_already.getCode())) {
                return Result.failure().message("本次挑战已领取奖励，不能重复领取").build();
            }
            recordPO.setStatus(BattleStatusEnum.received_already.getCode());
            mRecordBattleRecreationDAO.updateById(recordPO);
            prize = po.getPinecone();
        }
        DDetailsPineconePO sign = new DDetailsPineconePO();
        sign.setUserId(currentUser.getUserId());
        sign.setLabelType(LabelTypeEnum.challenge.getCode());
        sign.setDetailsType(DetailsTypeEnum.income.getCode());
        sign.setPinecone(prize);
        dDetailsPineconeDAO.save(sign);
        uAppUserEquityDAO.addPinecone(currentUser.getUserId(), prize);
        return Result.success().data(Boolean.TRUE).build();
    }

}
